package sshserver

import (
	"awesomeProject/goAgentServer/auth"
	"awesomeProject/goAgentServer/db"
	"awesomeProject/goAgentServer/encryption"
	"fmt"
	"github.com/gliderlabs/ssh"
	cryptoSSH "golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
	"io"
	"log"
	"os"
	"strconv"
	"strings"
)

func init() {
	log.SetPrefix("sshServers: ")
	log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}

func (u users) cacheHostsInfo() []userGroups {
	userCacheGroups := make([]userGroups, 0)

	var newGroupStrings string
	for _, group := range strings.Split(u.GroupIDs, ":") {
		var newGroup userGroups

		groupInfo, err := db.QueryGroupInfo(group)
		if err != nil {
			continue
		}

		if "" == newGroupStrings {
			newGroupStrings = group
		} else {
			newGroupStrings += fmt.Sprintf(":%v", group)
		}

		var newHostsString string
		for _, hostId := range strings.Split(groupInfo.HostsIDs, ":") {
			var newHost userHosts
			hostInfo, err := db.QueryHostsInfo(hostId)
			if err != nil {
				continue
			}

			if "" == newHostsString {
				newHostsString = hostId
			} else {
				newHostsString += fmt.Sprintf(":%v", hostId)
			}

			newHost.Ip = hostInfo.Addr
			newHost.Id = hostInfo.Id
			newHost.Remask = hostInfo.Remask

			newGroup.names = groupInfo.Names
			newGroup.hosts = append(newGroup.hosts, newHost)
		}
		if newHostsString != groupInfo.HostsIDs {
			db.ManageGroups(groupInfo.Names, newHostsString, groupInfo.Remask, "")
		}
		if newHostsString != "" {
			userCacheGroups = append(userCacheGroups, newGroup)
		}
	}
	if newGroupStrings != u.GroupIDs {
		db.ManageUsers(u.Username, []byte(""), newGroupStrings, u.Remask, -1)
	}
	return userCacheGroups
}

func readUserInputInfo(s ssh.Session) int {
	term = terminal.NewTerminal(s, fmt.Sprintf("\u001B[1;32;40m%s@No>\u001B[0m", s.User()))

	line, err := term.ReadLine()
	if err != nil {
		io.WriteString(s, fmt.Sprintf("\u001B[1;31;40m%s\n\u001B[0m", "readUserInput error"))
		return -2
	}
	if line == "quit" || line == "exit" || line == "xit" || line == "uit" {
		return -1
	}
	id, err := strconv.Atoi(line)
	if err != nil {
		io.WriteString(s, fmt.Sprintf("\u001B[1;31;40m%s\n\u001B[0m", "UnKnown IDs"))

		return -2
	}
	return id
}

func StartSshServer(address string) {
	ssh.Handle(sshHandle)
	sshServer := &ssh.Server{
		Addr: address,
		SubsystemHandlers: map[string]ssh.SubsystemHandler{
			"sftp": sftpHandler,
		},
		PasswordHandler: checkPasswd,
	}

	rsaString := "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA+t89N6ucj2ScHXKylIgaNHzHmGp//QfPLK//G8mgVSJQ3gwo\n2Ue8JcWmZWFKfIJufJkfVnX9tbDCWzeWtocG/VDWo7uNlI701g/9bolQ1tyL9+PO\nrI9nNSM+QpAwcl815FVV5yzXtVroP7wSTWP5JZ7wO3tm1HM0joNVLi8V9RdwIfbJ\ndS1foxERVJ/vW3Vo5CF0NH7ZY1JZ1/n2gQNcEt1BVITXeKAeES1T7YKP7dwQU85j\nagVXnNRIQltrlNnzrbHlbb5IY06Pp21TyiLNUzm8j1C4Fqa771aSVeLpSVDZ+iqR\n0dMMO1so2Pf3AR6qWiDpk010dDUCsCNE4nBsHQIDAQABAoIBAQC2uhmFzgq36wlG\n7b8jLssfhe9/lbrpm2GMZBjFraOJvvf19Bdgw75IKOGdIDM3420Edid8O27zgu7d\nr+ynwEwYAGSGV9q05TdyH61xcLUf+v48LYLg74a2DpiPtSSEedLwIDP0sRXg83kM\nyzjtg676dvz15lksz0jtsL0/aW5t2BZV5I4X2VZ28PHy308bYm7jfLnEiC3nWi+d\n4qh2uUfanSeqcEnsYYaeAVVBgXosiTiFPJgoy8Rl28339Q2jFI7ix2ObzSSvBKfX\nyzse04QfPo6uxoQQYh6XltjXxw9DC+6Ex8o1Rm/7am6bdAUjhLODVGw4C8+9XADJ\n5y4PWQDhAoGBAP9lnAaAXNaWPtux9KZtJ5Z8hbaDKecs0gAWjoZXOw0QdlwE8BGt\nMxwVGQ5UlbVdAQc3eIOJv8tIA9W9UrbcS7cWNdVAF6vJ6PK7In1cHwqS8dtpz0iO\nkoGKPFARuNppgFtwUTo5gmIApqNEu+pZMGr1ZdZpVc8HmfA6RA9VaIoVAoGBAPt2\n5PFzakzHpHFY7sA0TxYJheK48S6wHGbRvNXBuKgOZLeGNVOQ1VEk6xKFhgVmSw5w\nYgI7/TTXoEMiTVkw3eXjI15pcY8UD8kDw/nnwWJHR0jacIAXxc5Sj37sU0AqHJCI\nXf6c2qLOy5JTzmKE5pmTl60vYj8b8BGN+n77moPpAoGBAInxEo18ZShNrBOzESWW\njSw9g2bpfwdqcN41ULOEh9Ntkc/vps6VUqaXSpov21BCtFx2fHPnQZ0E/3VBNVyo\nrYhsyZStcluJyXTY2C8HQ4jNhy3v/1H8F2s6A4tnlwT4uKgqiOS+zQorudUzOZ/A\nnmMWufNNn1gbjexvO/VgNv9lAoGAY//d/57UMQBbhq/FEi47HRpgYc8GKnjicokJ\nvT+yfTJsHweCAV9hVUmHKfBrYY5SXsWWVCkjAnaVRt1HQSbLt3XiRNNN04Y42Mlk\nj+b34mtSD8i+YFIT2X6/jcvRN30Hqvpv1qbt0zzFe8VUF52eToiBEt/7A/nKOFDr\nwr+vrLECgYBrGEFUdAo12KD5iqzj5C5sPXa1ToO2MyBD+fcQld1L18DPJxb5wCvK\n5rCdxGLVojE8QbKfslcM/Kg8TmvW8m9cQ7YtHibM96Z/jEhMHelYMFwVl91p/ACC\nHh+2VnNUkLl5i3BuLgMjx35r/vlBdCi3rz0DeV7QeK4LiNOlmxMXOQ==\n-----END RSA PRIVATE KEY-----"

	signer, err := cryptoSSH.ParsePrivateKey([]byte(rsaString))
	if err != nil {
		log.Panicln("start ssh server error ", err)
	}

	sshServer.AddHostKey(signer)

	// 创建session目录
	_, err = os.Stat(SessionDir)
	if err != nil {
		if os.IsNotExist(err) {
			err = os.Mkdir(SessionDir, 0755)
			if err != nil {
				log.Println("create session dir error", err)
			}
		} else {
			log.Println("os stat sessiondir error", err)
		}
	}

	log.Println("start ssh server ", address)

	err = sshServer.ListenAndServe()
	if err != nil {
		log.Panicln(err)
	}
}

func checkPasswd(ctx ssh.Context, password string) bool {
	username := ctx.User()
	userInfo := db.QueryUserInfo(username)

	decrypyPassword, err := encryption.Decrypt(userInfo.Password)
	if err != nil {
		log.Println("jumpserver login failed,username: ", username, " encryption.Decrypt error ", err)
		return false
	}

	if auth.Authenticate([]byte(decrypyPassword), password, nil) {
		log.Println("jumpserver login ok,username:", username)
		return true
	}

	log.Println("jumpserver login failed,username:", username)
	return false
}
